package com.paradogs.framework.server;

import com.paradogs.common.utils.EventUtils;
import com.paradogs.common.utils.ProtoUtils;
import com.paradogs.common.utils.SpringUtils;
import com.paradogs.framework.annotations.ParadogsAnnotationsHolder;
import com.paradogs.framework.annotations.exceptionHandler.ParadogsExceptionHandlerManager;
import com.paradogs.framework.utils.ContextUtils;
import com.paradogs.framework.utils.MsgUtils;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.LinkedBlockingQueue;

/**
 * @author: yumi
 * @date: 2023/12/26  17:33
 * @Description: 游戏逻辑主处理线程：单线程
 */
@Slf4j
@Component
@EnableAsync
@Deprecated
public class ParadogsGameLogicHandleThreadSync implements ApplicationRunner {

    @Getter
    private static boolean RUNNING_FLAG = true;
    private static boolean RUNNING = true;

    // 消息处理队列
    public static LinkedBlockingQueue<ParadogsContext> messageQueue = new LinkedBlockingQueue<>();
    private static final ServerEvent.ServerUpdateEvent SERVER_UPDATE_EVENT = new ServerEvent.ServerUpdateEvent(new Object());

    /** 增加新消息到处理线程 */
    public static void join(ParadogsContext ctx) {
        messageQueue.add(ctx);
    }
    public static void join(Runnable exec) {
        messageQueue.add(new ParadogsContext(exec));
    }

    @Value("${server.min-world-update-time:1}")
    private long minUpdateDiff;

    /** 执行路由方法 */
    private void handleByRoute(ParadogsContext ctx) {

        Method method = ParadogsAnnotationsHolder.PRHandlerMap.get(ctx.getRoute());
        if (method == null) {
            throw new RuntimeException("Not found route: " + ctx.getRoute());
        }

        Object handlerObject = SpringUtils.getBean(method.getDeclaringClass()); // 处理类的实体 bean
        if (handlerObject == null) {
            throw new RuntimeException("Not Register HandlerClass: " + method.getDeclaringClass().getName());
        }

        // 自动注入参数并执行对应路由方法：参数1 = 消息对象，参数2 = 当前上下文
        Class<?>[] parameterTypes = method.getParameterTypes();
        Object result = null;
        try {
            switch (parameterTypes.length) {
                case 0: result = method.invoke(handlerObject); break;
                case 1: result = method.invoke(handlerObject, ProtoUtils.decode(ctx.getMessage().getDataBytes(), parameterTypes[0])); break;
                case 2: result = method.invoke(handlerObject, ProtoUtils.decode(ctx.getMessage().getDataBytes(), parameterTypes[0]), ctx); break;
            }
            if (result == null) { return; }
            // 将返回值作为回复消息进行发送
            if (result instanceof CompletableFuture) {
                // 异步返回
                ((CompletableFuture<?>) result)
                        .thenAccept(gc -> MsgUtils.notifyClient(ctx.getChannel(), MsgUtils.ROUTE_GC, gc, null, ctx.getMessage().getHeader().getId()))
                        .exceptionally(e -> {
                            ParadogsExceptionHandlerManager.forward(e, ctx); // 转发到全局消息处理器
                            throw new RuntimeException(); // 中止
                        });
            } else {
                // 同步返回
                MsgUtils.notifyClient(ctx.getChannel(), MsgUtils.ROUTE_GC, result, null, ctx.getMessage().getHeader().getId());
            }

        } catch (Exception e) {
            // 转发到全局消息处理器
            ParadogsExceptionHandlerManager.forward(e, ctx);
        }

    }

    @Async
    @Override
    public void run(ApplicationArguments args) {

//        log.info("GameLogicThread start ...");
//
//        /** 计算服务器下一帧时间并执行：参考 TrinityCore */
//        long realCurrTime = 0;
//        long realPrevTime = System.currentTimeMillis();
//        while (RUNNING_FLAG || messageQueue.size() > 0) {
//            realCurrTime = System.currentTimeMillis();
//            long diff /* deltaTime */ = realCurrTime - realPrevTime;
//            if (diff < minUpdateDiff) {
//                long sleepTime = minUpdateDiff - diff;
//                try {
//                    // 等待下一帧时间，有误差
//                    Thread.sleep(sleepTime);
//                } catch (InterruptedException e) {
//                    e.printStackTrace();
//                }
//                continue;
//            }
//            updateLoop(diff);
//            realPrevTime = realCurrTime;
//        }
//
//        log.info("GameLogicHandleThread stop ...");
//        RUNNING = false;
    }

    /** 处理服务器帧：TrinityCore 中这里会把遍历每个玩家，将每个消息队列取出 100 个消息尽量去处理
     * 所有跟我们的不太一样，框架是将消息放在了一个总的队列 */
    private void updateLoop(long deltaTime) {
        // 设置当前服务器帧间隔时间
        PDTime.DELTA = deltaTime;
        // 尝试从队列取出消息, 一帧最多处理 x 条消息
        for (int i = 0; i < 1000; i++) {
            ParadogsContext ctx = messageQueue.poll();
            if (ctx == null) { break; }
            /** 处理消息 */
            try {
                ContextUtils.setContext(ctx); // 设置上下文
                if (ctx.getExec() == null) {
                    // 普通路由消息
                    handleByRoute(ctx);
                } else {
                    // 方法类型消息（回调等）
                    ctx.getExec().run();
                }
            } catch (Exception e) {
                // 转发到全局异常处理
                ParadogsExceptionHandlerManager.forward(e, ctx);
            } finally {
                // 发布事件
                try {
                    if (ctx != null && ctx.getExec() == null) {
                        EventUtils.publishEvent(new ServerEvent.OneMessageHandleAfterEvent(ctx));
                    }
                } catch (Exception e) {
                    // 防止报错中断处理队列
                    log.error("{}", e);
                }

                // 释放上下文
                ContextUtils.release();
            }
        }

        // 服务器帧更新
        try {
            EventUtils.publishEvent(SERVER_UPDATE_EVENT);
        } catch (Exception e) {
            log.error("Server update err: {}", e.getMessage(), e);
        }
    }

    /** 停止线程 */
    public static void stop() {
        RUNNING_FLAG = false;
        ParadogsGameLogicHandleThreadSync.join(() -> {}); // 激活阻塞队列
    }

    /** 线程是否完全停止 */
    public static boolean isAlreadyStop() {
        return !RUNNING;
    }



}
